package com.bestv.search.management.datasyn;

import com.bestv.search.common.cache.SystemCache;
import com.bestv.search.common.dataSource.DataSourceKey;
import com.bestv.search.common.dataSource.DataSourceKeyUtil;
import com.bestv.search.common.model.AccessLog;
import com.bestv.search.common.model.ProgramSyncStatus;
import com.bestv.search.common.service.ProgramSyncStatusManager;
import com.bestv.search.common.util.StringConst;
import com.bestv.search.management.command.AccessLogCommand;
import com.bestv.search.management.xfire.ISearchWS;
import org.apache.log4j.Logger;
import org.codehaus.xfire.client.XFireProxyFactory;
import org.codehaus.xfire.service.Service;
import org.codehaus.xfire.service.binding.ObjectServiceFactory;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.util.StringUtils;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class AccessLogSync extends QuartzJobBean {

    private static boolean isRunning = false;
    private Logger logger = Logger.getLogger(AccessLogSync.class);
    private AccessLogCommand logCommand;
    private SystemCache systemCache;
    private int maxAnalyzeDays;
    private String logsFolder;
    private ProgramSyncStatusManager programSyncStatusManager;

    @Override
    protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {
        if (!isRunning) {
            try {
                isRunning = true;
                // local site code equals to local data source Key.
                String siteCode = systemCache.getLocalDataSourceKey();
                DataSourceKey key = DataSourceKeyUtil.convert(siteCode);
                Date now = Calendar.getInstance().getTime();

                ISearchWS service;
                Service serviceModel = new ObjectServiceFactory().create(ISearchWS.class);
                String url = systemCache.getWebServiceEngineUrls().get(siteCode);
                String[] soapUrls = StringUtils.tokenizeToStringArray(url, SystemCache.WEB_SERVICE_EURL_DELIMITERS);
                if (soapUrls == null || soapUrls.length == 0) {
                    logger.error("Gets info failed, no web service interface found from site " + siteCode);
                }

                for (int i = 0; i < soapUrls.length; i++) {
                    String soapUrl = soapUrls[i];
                    logger.debug("Get infomation from " + soapUrl);

                    String syncMessage = "Success sync accesslog from " + soapUrl + " @ " + now;
                    int serverNo = i + 1;

                    // get access log sync status
                    ProgramSyncStatus syncStatus = programSyncStatusManager.get(key, siteCode,
                            StringConst.BESTV_SEARCH_ENGINE, serverNo, StringConst.SEARCH_ENGINE_ACCESSLOG_SYNC_TIME);
                    try {
                        // If access log sync status is null, sync from
                        // 1990/01/01
                        Calendar c = Calendar.getInstance();
                        c.set(1990, 0, 1);
                        Date lastAnalyzeDate = c.getTime();
                        if (syncStatus != null) {
                            lastAnalyzeDate = syncStatus.getSyncSuccessTime();
                            if (lastAnalyzeDate == null) {
                                lastAnalyzeDate = c.getTime();
                            }
                        }

                        // gets AccessLogs from search engine
                        service = (ISearchWS) new XFireProxyFactory().create(serviceModel, soapUrl);
                        List<AccessLog> logs = service.accessLogSync(siteCode, serverNo, lastAnalyzeDate,
                                maxAnalyzeDays, logsFolder == null ? StringConst.EMPTY : logsFolder);

                        logCommand.saveAccessLogList(logs, systemCache.getLocalDataSourceKey());
                    } catch (Exception e) {
                        syncMessage = "Failed sync accesslog from " + soapUrl + " @ " + now;
                        logger.error(e);
                        e.printStackTrace();
                    } finally {
                        // update sync status to DB
                        if (syncStatus == null) {
                            syncStatus = new ProgramSyncStatus();
                            syncStatus.setSiteCode(systemCache.getLocalDataSourceKey());
                            syncStatus.setSysName(StringConst.BESTV_SEARCH_ENGINE);
                            syncStatus.setServerNo(serverNo);
                            syncStatus.setFieldName(StringConst.SEARCH_ENGINE_ACCESSLOG_SYNC_TIME);
                        }
                        syncStatus.setLastSyncTime(now);
                        syncStatus.setUpdateTime(now);
                        if (syncMessage.startsWith("Success")) {
                            // When sync successful, set LastSyncSuccessTime
                            syncStatus.setSyncSuccessTime(now);
                        }
                        syncStatus.setSyncMessage(syncMessage);

                        programSyncStatusManager.saveOrUpdate(key, syncStatus);
                    }
                    logger.info("End access log sync @" + new Date());
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                isRunning = false;
            }
        } else {
            logger.error("Last access log sync process is still running");
        }
    }

    public AccessLogCommand getLogCommand() {
        return logCommand;
    }

    public void setLogCommand(AccessLogCommand logCommand) {
        this.logCommand = logCommand;
    }

    public SystemCache getSystemCache() {
        return systemCache;
    }

    public void setSystemCache(SystemCache systemCache) {
        this.systemCache = systemCache;
    }

    public int getMaxAnalyzeDays() {
        return maxAnalyzeDays;
    }

    public void setMaxAnalyzeDays(int maxAnalyzeDays) {
        this.maxAnalyzeDays = maxAnalyzeDays;
    }

    public String getLogsFolder() {
        return logsFolder;
    }

    public void setLogsFolder(String logsFolder) {
        this.logsFolder = logsFolder;
    }

    public ProgramSyncStatusManager getProgramSyncStatusManager() {
        return programSyncStatusManager;
    }

    public void setProgramSyncStatusManager(ProgramSyncStatusManager programSyncStatusManager) {
        this.programSyncStatusManager = programSyncStatusManager;
    }
}